package com.chipcoo.shiro.session.mgt;

import com.chipcoo.IUserPrincipal;
import com.chipcoo.dao.impl.FingerMapperImpl;
import com.chipcoo.dao.impl.SessionMapperImpl;
import com.chipcoo.models.gen.Finger;
import com.chipcoo.utils.SecurityUtils;
import com.chipcoo.utils.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Date;

public final class MySqlSessionDAO extends EnterpriseCacheSessionDAO {
    @Autowired
    private SessionMapperImpl sessionMapper;
    @Autowired
    private FingerMapperImpl fingerMapper;

    private void buildExtraData(com.chipcoo.models.gen.Session sessionModel) {
        IUserPrincipal principal = SecurityUtils.getCurrentUser();
        if (null != principal) {
            sessionModel.setUserID(principal.getUserID());
            sessionModel.setIsAuthenticated(SecurityUtils.isAuthenticated());
        } else {
            sessionModel.setUserID(0);
            sessionModel.setIsAuthenticated(false);
        }
    }


    private void createUpdateSession(Session session) {

        com.chipcoo.models.gen.Session sessionModel=new com.chipcoo.models.gen.Session();

        sessionModel.setId(session.getId().toString());
        sessionModel.setUpdateAt(session.getLastAccessTime());

        if(session instanceof UserSession){

            UserSession userSession = (UserSession) session;
            sessionModel.setHost(userSession.getServerHost());
            sessionModel.setFingerID(userSession.getFingerID());

        }

        buildExtraData(sessionModel);

        if ( 0 == sessionMapper.updateByPrimaryKeySelective(sessionModel)) {

            sessionModel.setId(session.getId().toString());
            sessionModel.setCreatedAt(session.getStartTimestamp());
            sessionModel.setIp(StringUtils.ip2long(session.getHost()));

            sessionMapper.insertSelective(sessionModel);

            //session.setAttribute("s_last_to_db",new Date());
        }//else  session.setAttribute("s_last_to_db",new Date());

        if(!StringUtils.isEmpty(sessionModel.getFingerID())) {
            Finger fingerUpdate = new Finger();
            fingerUpdate.setId(sessionModel.getFingerID());

            fingerUpdate.setLastAccessed(new Date());
            fingerMapper.updateByPrimaryKeySelective(fingerUpdate);
        }
    }

    private Session retrieveSession(String sessionId){
        com.chipcoo.models.gen.Session sessionModel = sessionMapper.selectByPrimaryKey(sessionId);
        System.out.println(String.format("===========retrieveSession from db===%s=============",sessionId));
        if(null==sessionModel) return  null;
        else {
            UserSession userSession = new UserSession();
            userSession.setId(sessionModel.getId());
            userSession.setStartTimestamp(sessionModel.getCreatedAt());
            userSession.setLastAccessTime(new Date());
            userSession.setHost(StringUtils.long2ip(sessionModel.getIp()));

            userSession.setServerHost(sessionModel.getHost());
            userSession.setFingerID(sessionModel.getFingerID());

            return userSession;
        }
    }


   /* *//**
     * 为新会话，生产唯一ID，之后写入DB 废除 与 会触发doUpdate
     * @param session
     * @return
     *//*
    @Override
    public Serializable doCreate(final Session session) {
        super.doCreate(session);
        System.out.println(String.format("===========doCreate===%s=============",session.getId()));
        *//*new Thread(new Runnable() {
            @Override
            public void run() {
                createSession(session);
            }
        }).start();*//*
        createSession(session);
        return  session.getId();
    }*/


    /**
     * 修正缓存逻辑
     * @param sessionId
     * @return
     * @throws UnknownSessionException
     */
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        Session s = getCachedSession(sessionId);
        if (s == null) {
            s = doReadSession(sessionId);
            if (s == null) {
                throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
            } else {
                if (s instanceof ValidatingSession) {
                    if (((ValidatingSession) s).isValid()) {
                        cache(s, s.getId());
                    } else {
                        uncache(s);
                    }
                } else {
                    cache(s, s.getId());
                }
            }
        }
        return s;
    }
    /**
     * 从DB读取Session
     * @param sessionId
     * @return
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        if(null==sessionId) return null;
        return retrieveSession(sessionId.toString());
        //should never execute because this implementation relies on parent class to access cache, which
        //is where all sessions reside - it is the cache implementation that determines if the
        //cache is memory only or disk-persistent, etc.
    }


    @Override
    protected void doUpdate(final Session session) {

        if(session instanceof ValidatingSession) {
            if (((ValidatingSession) session).isValid()) {
                /*Object o = session.getAttribute("s_last_to_db");
                boolean saveToDB = null==o;
                if(!saveToDB){
                    long ts = new Date().getTime()-((Date)o).getTime();
                    if(ts>1000) saveToDB=true;
                }
                if(saveToDB) {
                    System.out.println(String.format("===========doUpdate==saved to db=%s=============",session.getId()));

                }*/
                createUpdateSession(session);
            }
        }
    }

    /**
     * 从DB删除Session
     * @param session
     */
    @Override
    protected void doDelete(  Session session) {


        System.out.println(String.format("===========removed from db===%s=============", session.getId()));
        sessionMapper.deleteByPrimaryKey(session.getId().toString());


    }
}
